package pl.com.hme.kody.pocztowe.http;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HttpContext;

import android.content.Context;
import android.text.format.DateUtils;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class HttpClientFactory {

    private static final int SECOND_IN_MILLIS = (int) DateUtils.SECOND_IN_MILLIS;

    private static final int TIMEOUT_IN_SEC = 300;

    private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
    private static final String ENCODING_GZIP = "gzip";

    private static String sUserAgent = null;
    private static DefaultHttpClient sHttpClient = null;
 
    /**
     * Generate and return a {@link HttpClient} configured for general use, including setting an application-specific user-agent string.
     * @param userAgent of created {@link HttpClient}. Can be null.
     * @return Configured {@link HttpClient}
     */
    public static HttpClient getHttpClient(String userAgent) {
        if (sHttpClient == null) {
            final HttpParams params = new BasicHttpParams();

            // Use generous timeouts for slow mobile networks
            HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_IN_SEC * SECOND_IN_MILLIS);
            HttpConnectionParams.setSoTimeout(params, TIMEOUT_IN_SEC * SECOND_IN_MILLIS);
            HttpConnectionParams.setTcpNoDelay(params, true);
            
            HttpConnectionParams.setSocketBufferSize(params, 8192);
            
            if(userAgent != null){
            	HttpProtocolParams.setUserAgent(params, userAgent);
            }
            
            sHttpClient = new DefaultHttpClient(params);

            sHttpClient.addRequestInterceptor(new HttpRequestInterceptor() {

                public void process(HttpRequest request, HttpContext context) {
                    // Add header to accept gzip content
                    if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
                        request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
                    }
                }
            });

            sHttpClient.addResponseInterceptor(new HttpResponseInterceptor() {

                public void process(HttpResponse response, HttpContext context) {
                    // Inflate any responses compressed with gzip
                    final HttpEntity entity = response.getEntity();
                    final Header encoding = entity.getContentEncoding();
                    if (encoding != null) {
                        for (HeaderElement element : encoding.getElements()) {
                            if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
                                response.setEntity(new InflatingEntity(response.getEntity()));
                                break;
                            }
                        }
                    }
                }
            });
        }

        return sHttpClient;
    }
    
    /**
     * Simple {@link HttpEntityWrapper} that inflates the wrapped {@link HttpEntity} by passing it through {@link GZIPInputStream}.
     */
    private static class InflatingEntity extends HttpEntityWrapper {

        public InflatingEntity(HttpEntity wrapped) {
            super(wrapped);
        }

        @Override
        public InputStream getContent() throws IOException {
            return new GZIPInputStream(wrappedEntity.getContent());
        }

        @Override
        public long getContentLength() {
            return -1;
        }
    }

    public static String getUserAgentString(Context context) {
        if (sUserAgent == null) {
            try {
                Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
                constructor.setAccessible(true);
                try {
                    WebSettings settings = constructor.newInstance(context, null);
                    sUserAgent = settings.getUserAgentString();
                } finally {
                    constructor.setAccessible(false);
                }
            } catch (Exception e) {
                sUserAgent = new WebView(context).getSettings().getUserAgentString();
            }
        }
        return sUserAgent;

    }

}
